package com.wzapp.sitposture.usercenter.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wzapp.sitposture.authentication.pojo.entity.AuthUser;
import com.wzapp.sitposture.common.base.HeaderParam;
import com.wzapp.sitposture.common.constant.UserConst;
import com.wzapp.sitposture.common.error.CustomizedException;
import com.wzapp.sitposture.common.exception.AuthenticationException;
import com.wzapp.sitposture.common.page.PageParam;
import com.wzapp.sitposture.common.util.BeanUtil;
import com.wzapp.sitposture.common.util.MD5Util;
import com.wzapp.sitposture.common.util.PageUtil;
import com.wzapp.sitposture.common.util.ToolUtil;
import com.wzapp.sitposture.config.redis.service.RedisService;
import com.wzapp.sitposture.config.redission.annotation.RedisLock;
import com.wzapp.sitposture.eshop.entity.Order;
import com.wzapp.sitposture.eshop.service.OrderService;
import com.wzapp.sitposture.setup.entity.City;
import com.wzapp.sitposture.setup.entity.Setup;
import com.wzapp.sitposture.setup.repository.CityRepository;
import com.wzapp.sitposture.setup.service.SetupService;
import com.wzapp.sitposture.usercenter.entity.User;
import com.wzapp.sitposture.usercenter.entity.UserConfig;
import com.wzapp.sitposture.usercenter.entity.UserIncome;
import com.wzapp.sitposture.usercenter.entity.UserLoginLog;
import com.wzapp.sitposture.usercenter.repository.UserConfigRepository;
import com.wzapp.sitposture.usercenter.repository.UserIncomeRepository;
import com.wzapp.sitposture.usercenter.repository.UserLoginLogRepository;
import com.wzapp.sitposture.usercenter.repository.UserRepository;
import com.wzapp.sitposture.usercenter.service.HuanXinService;
import com.wzapp.sitposture.usercenter.service.UserService;
import com.wzapp.sitposture.usercenter.view.RingAccountDTO;
import com.wzapp.sitposture.usercenter.view.UserDTO;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by qianglong on 2018/1/16.
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    public static final long EXPIRE_TIME = 100L;

    @Autowired
    private RedisService redisService;

    @Autowired
    UserRepository userRepository;

    @Autowired
    CityRepository cityRepository;

    @Autowired
    SetupService setupService;

    @Autowired
    UserLoginLogRepository userLoginLogRepository;

    @Autowired
    private JPAQueryFactory queryFactory;

    @Autowired
    HttpServletRequest httpServletRequest;

    @Autowired
    UserConfigRepository userConfigRepository;

    @Autowired
    HuanXinService huanXinService;

    @Autowired
    UserIncomeRepository userIncomeRepository;

    @Autowired
    OrderService orderService;

    @Value("${spring.profiles.active}")
    private String profile;

    @Override
    @RedisLock(key = "UserServiceImpl.register")
    public User register(User user) throws IOException, CustomizedException {

        //如果注册时已存在
        User userDB = userRepository.findByMobile(user.getMobile());
        if (null!=userDB){
            User resUser = this.getFullUserById(userDB.getId());
            //判断是否是第一次登陆用
            resUser.setNewUser(true);
            return resUser;
        }

        //recommendCode不为null，分销关系保存
        String recommendCode = user.getRecommendCode();
        if(ToolUtil.isNotEmpty(recommendCode)){
            User parentUser = userRepository.findTop1ByRecommendCodeIgnoreCase(recommendCode.trim());
            if(parentUser == null){
                throw new CustomizedException("userCenter.recommendCode.error");
            }
            user.setParentId(parentUser.getId());
        }

        // 随机选择一个头像设置给用户,需OA配置，目前没有要求，app前端自己展示默认图片
        List<Setup> defaultAvatars = setupService.findByGroupType("default_avatar",null);
        if (ToolUtil.isNotEmpty(defaultAvatars)) {
            Setup selectAvatar = defaultAvatars.get(ToolUtil.getRandomInt(defaultAvatars.size()));
            JSONObject object = selectAvatar.getData();
            user.setAvatar(object.getString("url"));
        }

        String salt = ToolUtil.getRandomString(32);
        user.setSalt(salt);
        user.setPassword(MD5Util.encrypt(user.getPassword(), salt));

        user.setLevel(UserConst.DEFAULT_LEVEL);
        user.setStatus(UserConst.STATUS_ENABLED);
        user.setSex(UserConst.SEX_X);

        //生成分销编码
        user.setRecommendCode(this.unRepeatSixCode());
        //ios对于null不支持，所以写入空字符
        if(ToolUtil.isEmpty(user.getAccount())){
            user.setAccount("");
        }

        userDB = userRepository.save(user);
        //补充路由信息
        userDB.setRouter(this.getRouter(userDB.getId()));

        //TODO 注册环信家长和学生账号
        String nickName = userDB.getAccount();
        if(ToolUtil.isEmpty(nickName)){
            nickName = userDB.getMobile();
        }
        List<RingAccountDTO> ringAccountDTOS = huanXinService.createUser(userDB.getId(),user.getPassword(),nickName);
        userDB.setRingAccount(JSONArray.parseArray(JSON.toJSONString(ringAccountDTOS)));

        //生成学习配置
        UserConfig userConfig = new UserConfig();
        userConfig.setId(userDB.getId());
        userConfigRepository.saveAndFlush(userConfig);

        User resUser = this.getFullUserById(userDB.getId());
        //判断是否是第一次登陆用
        resUser.setNewUser(true);
        //创建订单
        this.createOrder(resUser);

        return resUser;
    }

    private void createOrder(User user){
        //免费试用天数
        JSONObject jsonObject = setupService.findOneByGroupType("freeDays");
        int freeDays = jsonObject.getIntValue("freeDays");
        if(freeDays < 1){
            //产品费用
            JSONObject jsonObject2 = setupService.findOneByGroupType("productFee");
            Double productFee = jsonObject2.getDoubleValue("productFee");

            Order order = new Order();
            order.setUserId(user.getId());
            order.setAmount(productFee);
            order.setPayAmount(productFee);
            order.setRecommendUserId(user.getParentId());
            try {
                orderService.createOrderInfo(order);
            }catch (CustomizedException e){
                log.error("===========注册后直接创建订单失败=========userId={},userName={}======",user.getId(),user.getAccount());
                log.error("==============注册后直接创建订单原因===e={}==========",e.getMessage());
            }
        }

    }

    @RedisLock(key = "UserServiceImpl.unRepeatSixCode")
    public String unRepeatSixCode() {

        String sixChar = "";
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
        Date date = new Date();
        String time = sdf.format(date);
        for (int i = 0; i < time.length() / 2; i++) {
            String singleChar;
            String x = time.substring(i * 2, (i + 1) * 2);
            int b = Integer.parseInt(x);
            if (b < 10) {
                singleChar = Integer.toHexString(Integer.parseInt(x));
            } else if (b >= 10 && b < 36) {
                singleChar = String.valueOf((char) (Integer.parseInt(x) + 55));
            } else {
                singleChar = String.valueOf((char) (Integer.parseInt(x) + 61));
            }
            sixChar = sixChar + singleChar;

        }
        return sixChar;
    }

    @Transactional
    @Override
    public Map loginByAccount(String account, String password,String signOs) throws CustomizedException {
        //构造返回信息
        Map map = new HashMap();

        //先用它去匹配手机号码，是否手机号码登录
        User userDB = this.getUserByMobile(account);
        map.put("loginType", "mobile");

        if(ToolUtil.isEmpty(userDB)){
            throw new AuthenticationException("userCenter.account.password.is.error");
        }

        this.verifyAccount(userDB.getStatus());

        String passwordDB = userDB.getPassword();
        String salt = userDB.getSalt();
        //兼容割接数据
        if (!passwordDB.equals(MD5Util.encrypt(password, salt))) {
            throw new AuthenticationException("userCenter.account.password.is.error");
        }

        if(ToolUtil.isNotEmpty(signOs) && "ios".equalsIgnoreCase(signOs)  && userDB.getIosUser() != 1){
            //标记ios购买用户
            userDB.setIosUser(1);
            userRepository.saveAndFlush(userDB);
            // 标记待支付订单支付成功
            Order orderDB = orderService.getUserOrderByUserId(userDB.getId());
            if(orderDB != null){
                orderService.processPayOrderSuccess(orderDB.getId(),4,null);
            }
        }

        userDB = this.getFullUserById(userDB.getId());
        map.put("user", userDB);
        return map;
    }

    @Override
    public User resetPassword(User user, String newPassword) throws CustomizedException {

        User userDB = userRepository.findOne(user.getId());

        this.verifyAccount(userDB.getStatus());

        String salt = ToolUtil.getRandomString(32);
        userDB.setSalt(salt);
        userDB.setPassword(MD5Util.encrypt(newPassword, salt));
        userRepository.save(userDB);

        return this.getFullUserById(userDB.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User updateUser(User user, HeaderParam headerParam) throws CustomizedException {

        //更新用户信息
        modifyUser(user, headerParam);

        User userDB = this.getFullUserById(user.getId());
        return userDB;
    }

    @Transactional(rollbackFor = Exception.class)
    public void modifyUser(User user, HeaderParam headerParam) throws CustomizedException {

        String id = user.getId();
        User userDB = userRepository.findOne(id);
        if (ToolUtil.isEmpty(userDB)) {
            throw new CustomizedException("userCenter.user.not.exists.error");
        }

        //忽略密码修改
        BeanUtil.copyPropertiesIgnoreNull(user,userDB,"password");

        //防止被覆盖
        if (ToolUtil.isNotEmpty(user.getCityId()) && ToolUtil.isEmpty(user.getCityName())) {
            City city = cityRepository.findOne(user.getCityId());
            if (ToolUtil.isNotEmpty(city)) {
                String address = city.getProvince() + " " + city.getCity();
                userDB.setAddress(address);
                userDB.setCityName(city.getCity());
            }
        }

        userRepository.saveAndFlush(userDB);
    }

    @Override
    public User getUserById(String id) {

        User user = userRepository.findOne(id);
        if (user == null) {
            return null;
        }

        //脱离数据链接关系，不然以下修改，会被update
        User newUser = new User();
        //复制忽略密码值
        BeanUtils.copyProperties(user, newUser,"password");

        return newUser;
    }

    @Override
    public User findUserByRecommendCode(String recommendCode) {

        User user = userRepository.findTop1ByRecommendCodeIgnoreCase(recommendCode);

        if (user == null) {
            return null;
        }

        //脱离数据链接关系，不然以下修改，会被update
        User newUser = new User();
        //复制忽略密码值
        BeanUtils.copyProperties(user, newUser,"password");

        return newUser;
    }

    @Override
    public User getFullUserById(String id) throws CustomizedException {

        User user = this.getUserById(id);
        return user;
    }

    @Override
    public Boolean isExists(String mobile) {
        User user = userRepository.findByMobile(mobile);
        if(user != null){
            return true;
        }
        return false;
    }

    @Override
    @Cacheable(value = "getSimpleUserById", key = "#id", condition = "#id != null")
    public UserDTO getSimpleUserById(String id) {

        User user = userRepository.findOne(id);
        if (user == null) {
            return null;
        }

        UserDTO userDTO = new UserDTO();
        BeanUtil.copyPropertiesIgnoreNull(user, userDTO);

        return userDTO;
    }

    @Override
    public User getUserByMobile(String mobile) {

        return userRepository.findByMobile(mobile);
    }

    @Override
    public void publishLoginLogEvent(HashMap<String, Object> param) {

        UserLoginLog userLoginLog = (UserLoginLog) param.get("userLoginLog");

        userLoginLogRepository.saveAndFlush(userLoginLog);
    }

    @Override
    public void publishLogOutLogEvent(HashMap<String, Object> param) {

        String userId = (String) param.get("userId");
        Long logOutTime = (Long) param.get("logoutTime");
        String terminalType = (String) param.get("terminalType");

        UserLoginLog userLoginLog = userLoginLogRepository.findTop1ByUserIdAndTerminalTypeAndLogoutTimeIsNullOrderByCreateTimeDesc(userId, terminalType);

        if (userLoginLog != null) {
            userLoginLog.setLogoutTime(logOutTime);
            userLoginLog.setLoginDuration(logOutTime - userLoginLog.getLoginTime());
            userLoginLog.setUpdateTime(System.currentTimeMillis());
            userLoginLogRepository.saveAndFlush(userLoginLog);
        }

    }


    @Override
    public UserConfig findUserConfigById(String userId) {

        return userConfigRepository.findOne(userId);
    }

    @Override
    public UserConfig updateUserConfig(UserConfig userConfig) {

        UserConfig userConfigDB = userConfigRepository.findOne(userConfig.getId());

        if(userConfigDB == null){
            userConfigDB = new UserConfig();
        }
        BeanUtil.copyPropertiesIgnoreNull(userConfig,userConfigDB);

        return userConfigRepository.saveAndFlush(userConfigDB);
    }

    @Override
    public Page findIncomeByUserId(String userId, PageParam pageParam) {

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = PageUtil.convertToPageable(pageParam,sort);

        return userIncomeRepository.findIncomeByUserId(userId,pageable);
    }

    @Override
    public List<User> findNewUserByCreateTime(Integer freeDays) {
        return userRepository.findNewUserByCreateTime(freeDays);
    }

    @Override
    public void saveUserIncome(List<UserIncome> userIncomeList) {
        userIncomeRepository.save(userIncomeList);
        userIncomeRepository.flush();
    }

    @Override
    public List<String> findUnpaidUserByCreateTime() {
        return userRepository.findUnpaidUserByCreateTime();
    }

    /**
     * 功能: 验证账户有效性<br/>
     *
     * @param status
     * @return void
     * @author ql
     * @create 2018/1/28 11:14
     **/
    private void verifyAccount(Integer status) {

        //账号冻结后不可登录
        if (UserConst.STATUS_FREEZE.equals(status)) {
            throw new AuthenticationException("userCenter.user.status.freeze");
        }
        //账号注销后不可登录
        if (UserConst.STATUS_CANCELLATION.equals(status)) {
            throw new AuthenticationException("userCenter.user.status.cancellation");
        }
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Object loginType = httpServletRequest.getAttribute("loginType");
        //手机号登录mobile
        User user = null;
        //默认设置为手机号登录
        if (null == loginType || loginType.equals("mobile")) {
            user = userRepository.findByMobile(username);
        } else {
            user = userRepository.findOneByAccount(username);
        }

        return new AuthUser(user.getId(), user.getPassword(), user.getSalt(), user.getAuthorities());
    }

    private String getRouter(String userId){
        return "/home?userId=" + userId;
    }

}

